
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <dirent.h>

#include <sys/ioctl.h>
#include <sys/types.h>
#include <syslog.h>
#include <ctype.h>
#include <math.h>

#include "record_ctrl.h"
#include "monitor.h"

#include "ak_common.h"
#include "ak_thread.h"

#include "ak_vi.h"
#include "ak_ai.h"
#include "ak_ao.h"
#include "ak_aenc.h"
#include "ak_its.h"

#include "ak_config.h"
#include "ak_rtsp.h"
#include "ak_net.h"
#include "ak_onvif.h"
#include "ak_dana.h"
#include "ak_csrv.h"
#include "ak_misc.h"

#include "ak_common.h"
#include "ak_thread.h"
#include "ak_vi.h"
#include "ak_venc.h"

#include  <unistd.h>
#include  <sys/types.h>       /* basic system data types */
#include  <sys/socket.h>      /* basic socket definitions */
#include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */
#include  <arpa/inet.h>       /* inet(3) functions */
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/statfs.h>
#include "ak_common.h"

/* anyka_ipc platform version */
#define AK_VERSION_SOFTWARE             "A921_V02.01.04_0828"

/* ISP config file path */
#define FIRST_PATH       				"/etc/jffs2/"
#define BACK_PATH        				"/usr/local/"

#define IPC_AI_MAX_VOLUME				8

/* make sure vi, ai and ao open just once */
static void *vi_handle = NULL;
static void *ai_handle = NULL;
static void *ao_handle = NULL;

void *venc_handle;					//video encode handle
void *stream_handle;

#define MAXLINE 1024
#define BUFF_SIZE 2*1024*1024
#define SendLen   40*1024

unsigned char g_spsppsbuf[BUFF_SIZE]={0};
unsigned char g_spsppslen=0;
int listenq = 1024;
int g_GetPackFlag=0;

unsigned char g_aacbuf[200*1024]={0};
int g_aac_len = 0;
int g_GetPackAudioFlag=0;

int tmp_android;
int socket_handle_audio;
int g_b_I_frame_cap=0;

unsigned char g_buf[BUFF_SIZE];
int g_len;

struct aenc_demo {
	int save_time;		/* save time */
	char *save_path;	/* save file path */
	FILE *fp;			/* save file handle */
};
struct aenc_demo aenc = {0};

static unsigned char ipc_run_flag = 0;

int udc_value = 0;
int save_last_flag = 0;
int same_num = 0;
const char* ak_ipc_get_verion(void)
{
	return AK_VERSION_SOFTWARE;
}

/*
 * parse_cmd - parse cmd callback
 * cmd_buf[IN]: cmd will be parse
 */
static void parse_cmd(char *cmd_buf)
{
	const char delim[] = ",";
	char *cmd = NULL, *arg = NULL;

	if (!strlen(cmd_buf))
		return;

	/* dividide string to get cmd and argument */
	ak_print_info_ex("cmd buf: %s\n", cmd_buf);
	cmd = strtok(cmd_buf, delim);
	if (cmd) {
		ak_print_info_ex("get cmd: %s\n", cmd);
		arg = strtok(NULL, delim);
	}

	/* parse and execute */
	if (cmd && arg) {
		/* tips */
		if (strcmp(cmd, "tips") == 0) {
			ak_print_info_ex("play %s\n", arg);
			/* now we set only 8k and 16bit one channel mp3 tips */
			struct audio_param file_param = {AK_AUDIO_TYPE_MP3, 8000, 16, 1};
			ak_misc_add_voice_tips(arg, &file_param);
		}

		/* ircut switch */
		if (strcmp(cmd, "ircut") == 0) {
			int day_night = atoi(arg);
			ak_print_normal_ex("switch ircut, %s\n", day_night ? "day": "night");

			struct camera_disp_config *camera = ak_config_get_camera_info();
			ak_misc_set_video_day_night(vi_handle, day_night, camera->day_ctrl);
		}

		/* photosensitive pattern enable/disable */
		if (strcmp(cmd, "photosensitive") == 0) {
			/* 0 disable, 1 enable */
			int enable = atoi(arg);
			ak_misc_switch_photosensitive_ircut(enable);
		}

		/* its start/stop */
		if (strcmp(cmd, "its") == 0) {
			/* 0 stop, 1 start */
			int start = atoi(arg);

			if (start)
				ak_its_start();
			else
				ak_its_stop();
		}
	}
}

/**
 * exit_ipc_app - release_ipc_resource
 * @void
 * return: void
 * notes: call this function when you stop and exit ipc program
 */
static void exit_ipc_app(void)
{
	ak_print_normal("\n********** entering ipc_exit_app **********\n");
	struct sys_cloud_config *cloud = ak_config_get_sys_cloud();

	/* set log level to info, to dump more message */
	int old_level = ak_print_set_level(LOG_LEVEL_INFO);

#ifdef CONFIG_ONVIF_SUPPORT
	if(cloud->onvif && !cloud->rtsp){
		ak_onvif_exit();
	}
#endif

#ifdef CONFIG_RTSP_SUPPORT
	if(cloud->rtsp && !cloud->onvif) {
		ak_rtsp_exit();
		ak_print_normal_ex("######## rtsp exit ok ########\n");
	}
#endif

#ifdef CONFIG_DANA_SUPPORT
	if(cloud->dana && !cloud->tencent){
		ak_dana_exit();
	}
#endif

	struct video_record_config *record = ak_config_get_record();
	if (record->server_flag) {
		if(cloud->tencent || cloud->dana){
			record_ctrl_exit();
		}
	}

	ak_print_notice_ex("*** ready to close vi, ai and ao ***\n");
	if (vi_handle) {
		ak_vi_close(vi_handle);
		vi_handle = NULL;
	}
	if (ai_handle) {
		ak_ai_close(ai_handle);
		ai_handle = NULL;
	}
	if (ao_handle) {
		ak_ao_close(ao_handle);
		ao_handle = NULL;
	}
	ipc_run_flag = 0;

	/* exit the voice play module */
	ak_misc_exit_voice_tips();

	ak_csrv_cmd_exit_server();

	ak_misc_stop_photosensitive_switch();

	ak_print_set_level(old_level);

	ak_print_normal("\n********** Anyka IPC program exit OK **********\n");
}

static void init_hardware(void)
{
#if 0
	PTZControlInit();
	sd_init_status();

	pthread_t ircut_pth_id;
	anyka_pthread_create(&ircut_pth_id, camera_ircut_pthread,
			NULL, ANYKA_THREAD_MIN_STACK_SIZE, 1);
#endif
}

static int init_vi(void)
{
	/* open device */
	vi_handle = ak_vi_open(VIDEO_DEV0);
	if (NULL == vi_handle) {
		ak_print_error_ex("vi open failed\n");
		return AK_FAILED;
	}

	/* get camera resolution */
	struct video_resolution resolution = {0};
	if (ak_vi_get_sensor_resolution(vi_handle, &resolution))
		ak_print_error_ex("get sensor resolution failed\n");

	/* set crop information */
	struct video_channel_attr attr;
	struct camera_disp_config *camera = ak_config_get_camera_info();

	if (camera->main_width > resolution.width) {
		ak_print_error_ex("ini file's width invalid, only can be %d\n",
			resolution.width);
		camera->main_width = resolution.width;
	}
	if (camera->main_height > resolution.height) {
		ak_print_error_ex("ini file's height invalid, only can be %d\n",
			resolution.height);
		camera->main_height = resolution.height;
	}

	memset(&attr, 0x00, sizeof(attr));
	attr.res[VIDEO_CHN_MAIN].width = camera->main_width;
	attr.res[VIDEO_CHN_MAIN].height = camera->main_height;
	attr.res[VIDEO_CHN_SUB].width = camera->sub_width;
	attr.res[VIDEO_CHN_SUB].height = camera->sub_height;
	attr.crop.left = 0;
	attr.crop.top = 0;
	attr.crop.width = camera->main_width;
	attr.crop.height = camera->main_height;

	if (ak_vi_set_channel_attr(vi_handle, &attr)) {
		ak_print_error_ex("set channel attribute failed\n");
	}

	/* get crop */
	struct video_channel_attr cur_attr;

	memset(&cur_attr, 0x00, sizeof(cur_attr));
	if (ak_vi_get_channel_attr(vi_handle, &cur_attr)) {
		ak_print_normal("ak_vi_get_channel_attr failed!\n");
	}

	ak_print_normal_ex("capture fps: %d\n", ak_vi_get_fps(vi_handle));
	ak_print_normal("\nvideo input info:\n"
			"\tmain_w[%d], main_h[%d], sub_w[%d], sub_h[%d]\n\n",
			camera->main_width, camera->main_height,
			camera->sub_width, camera->sub_height);
	/* set capture fps */	
	ak_vi_set_fps(vi_handle, 25);	
	ak_print_normal("\tcapture fps: %d\n", ak_vi_get_fps(vi_handle));
	return AK_SUCCESS;
}

/* match sensor according to ISP config file path */
static int match_sensor(const char *isp_cfg_path)
{
	DIR *dir = opendir(isp_cfg_path);
	if (NULL == dir) {
		ak_print_normal_ex("it fails to open directory %s\n", isp_cfg_path);
		return 0;
	}

	int ret = AK_FAILED;
	char isp_file[255] = {0};
	char *tmp = NULL;
	char *isp_cfg = NULL;
	struct dirent *dir_ent = NULL;

	while (NULL != (dir_ent = readdir(dir))) {
		if (!dir_ent->d_name)
			continue;

		/* fine next when we get dir */
        if ((dir_ent->d_type & DT_DIR)) {
            continue;
        }

		/* make sure use isp_*.conf file to match */
		tmp = strstr(dir_ent->d_name, "isp_");
		if (!tmp) {
			continue;
		}

		isp_cfg = strstr(tmp, ".conf");
		if (!isp_cfg) {
			continue;
		}

		sprintf(isp_file, "%s%s", isp_cfg_path, dir_ent->d_name);
		/* get sensor id, match config file */
		if(AK_SUCCESS == ak_vi_match_sensor(isp_file)){
			ak_print_notice_ex("ak_vi_match_sensor OK\n");
			ret = AK_SUCCESS;

			if (strcmp(isp_cfg_path, FIRST_PATH))
			{
				char cmd[128] = {0};

				sprintf(cmd, "cp %s %s", isp_file, FIRST_PATH);
				system(cmd);

				sprintf(isp_file, "%s%s", FIRST_PATH, dir_ent->d_name);
				ak_vi_match_sensor(isp_file);
			}
			break;
		}
	}
	closedir(dir);

	return ret;
}

static int init_video(void)
{
	/* match sensor at the first step */
	if (AK_FAILED == match_sensor(FIRST_PATH)) {
		ak_print_warning_ex("match_sensor FIRST_PATH failed\n");
		if (AK_FAILED == match_sensor(BACK_PATH)) {
			ak_print_error_ex("match_sensor BACK_PATH failed\n");
			return AK_FAILED;
		}
	}

	int ret = AK_FAILED;

	/* one video input device, only open one time vi for encode */
	if (init_vi()) {
		ak_print_error_ex("video input init faild, exit\n");
	} else {
		ak_print_notice_ex("start capture ...\n");
		if(ak_vi_capture_on(vi_handle)) {
			ak_print_error_ex("vi capture on failed\n");
		} else {
			ret = AK_SUCCESS;
		}
	}

	if ((AK_FAILED == ret) && (NULL != vi_handle)) {
		ak_vi_close(vi_handle);
		vi_handle = NULL;
	}

	return ret;
}

static int init_ai(void)
{
	struct pcm_param ai_param = {0};
	struct video_record_config *record_config = ak_config_get_record();

	/* set correct param to open audio input */
	ai_param.sample_bits = 16;
	/* channel number only support AUDIO_CHANNEL_MONO */
	ai_param.channel_num = AUDIO_CHANNEL_MONO;
	ai_param.sample_rate = record_config->sample_rate;

	ai_handle = ak_ai_open(&ai_param);
	if(NULL == ai_handle){
		return AK_FAILED;
	}

	/* set ai attributions after open OK */
	ak_ai_set_aec(ai_handle, AUDIO_FUNC_DISABLE);
	ak_ai_set_nr_agc(ai_handle, AUDIO_FUNC_DISABLE);
	ak_ai_set_resample(ai_handle, AUDIO_FUNC_ENABLE);
	// ak_ai_set_volume(ai_handle, IPC_AI_MAX_VOLUME);
	ak_ai_set_volume(ai_handle, 7);
	ak_ai_clear_frame_buffer(ai_handle);

	return AK_SUCCESS;
}

static int init_ao(void)
{
	struct pcm_param ao_param = {0};
	ao_param.sample_bits = 16;
	/* driver always set to AUDIO_CHANNEL_STEREO, so you don't care */
	ao_param.channel_num = AUDIO_CHANNEL_MONO;
	ao_param.sample_rate = 8000;

    ao_handle = ak_ao_open(&ao_param);
    if(NULL == ao_handle) {
    	return AK_FAILED;
    }

	/* set ao attributions after open OK */
	ak_ao_enable_speaker(ao_handle, AUDIO_FUNC_ENABLE);
	ak_ao_set_volume(ao_handle, 6);
	ak_ao_set_resample(ao_handle, AUDIO_FUNC_ENABLE);
	ak_ao_clear_frame_buffer(ao_handle);

	return AK_SUCCESS;
}

static int init_audio(void)
{
	if (AK_FAILED == init_ai()) {
		ak_print_error_ex("init ai failed\n");
		return AK_FAILED;
	}
	ak_print_notice_ex("init audio in OK\n");

	int ret = init_ao();
	if (AK_FAILED == ret) {
		ak_print_error_ex("init ao failed\n");
	}
	ak_print_notice_ex("init audio out OK\n");

	return ret;
}

#ifdef CONFIG_ONVIF_SUPPORT
static void set_onvif_net_param(const struct onvif_net_param *net)
{
    struct sys_net_config *param = ak_config_get_sys_net();

	param->dhcp = net->dhcp;
	strcpy(param->ipaddr, net->ipaddr);
	strcpy(param->netmask, net->netmask);
	strcpy(param->gateway, net->gateway);
	strcpy(param->firstdns, net->firstdns);
	strcpy(param->backdns, net->backdns);

	ak_config_set_sys_net(param);
	ak_config_flush_data();
}

static void set_onvif_video_param(const struct onvif_video_param *video)
{
    struct sys_onvif_config *onvif = ak_config_get_sys_onvif();
    struct camera_disp_config *camera = ak_config_get_camera_info();

    if (VIDEO_CHN_MAIN == video->channel) {
        onvif->main_kbps = video->main_kbps;
	    onvif->main_fps = video->main_fps;

	    camera->main_width = video->main_width;
	    camera->main_height = video->main_height;
    } else {
        onvif->sub_kbps = video->sub_kbps;
    	onvif->sub_fps = video->sub_fps;

    	camera->sub_width = video->sub_width;
    	camera->sub_height = video->sub_height;
    }

    ak_config_set_sys_onvif(onvif);
    ak_config_set_camera_info(camera);
    ak_config_flush_data();
}

static void init_onvif(void)
{
    struct onvif_param param = {0};

    param.vi_handle = vi_handle;

    struct camera_disp_config *camera = ak_config_get_camera_info();

    /* camera config */
    param.main_width = camera->main_width;
    param.main_height = camera->main_height;
    param.sub_width = camera->sub_width;
    param.sub_height = camera->sub_height;

    /* osd config */
	param.osd_rate = camera->osd_rate;
	param.osd_position = camera->osd_position;
    param.osd_switch = camera->osd_switch;
    strcpy(param.osd_name, camera->osd_name);
    param.time_switch = camera->time_switch;
    param.date_format = camera->date_format;
    param.hour_format = camera->hour_format;
    param.week_format = camera->week_format;

    /* encode config*/
    struct video_config *video = ak_config_get_sys_video();
    param.gop_len = video->gop_len;
    param.min_qp = video->min_qp;
    param.max_qp = video->max_qp;
    param.video_mode = video->video_mode;
    param.method = video->method;

    /* onvif config */
    struct sys_onvif_config *onvif = ak_config_get_sys_onvif();
    param.main_fps = onvif->main_fps;
    param.main_kbps = onvif->main_kbps;
    param.sub_fps = onvif->sub_fps;
    param.sub_kbps = onvif->sub_kbps;

    param.net_cb = set_onvif_net_param;
    param.video_cb = set_onvif_video_param;

    ak_onvif_init(&param);
}
#endif

 #ifdef CONFIG_RTSP_SUPPORT
// static void init_rtsp(void)
// {
//     struct rtsp_param param = {0};

//     param.vi_handle = vi_handle;

//     struct camera_disp_config *camera = ak_config_get_camera_info();

//     /* camera config */
//     param.main_width = camera->main_width;
//     param.main_height = camera->main_height;
//     param.sub_width = camera->sub_width;
//     param.sub_height = camera->sub_height;

//     /* video encode config*/
//     struct video_config *video = ak_config_get_sys_video();
//     param.min_qp = video->min_qp;
//     param.max_qp = video->max_qp;
//     param.gop_len = video->gop_len;
//     param.video_mode = video->video_mode;
//     param.method = video->method;

//     /* rtsp config */
//     param.v720p_fps = video->v720p_fps;
//     param.v720p_max_kbps = video->v720p_max_kbps;
//     param.vga_fps = video->vga_fps;
//     param.vga_max_kbps = video->vga_max_kbps;

//     if (ak_rtsp_init(&param)){
// 		ak_print_error_ex("######## rtsp init failed ########\n");
// 	} else {
//         ak_print_normal("start rtsp OK\n");
// 	}
// }
#endif

/*
 * venc_switch_resulution - switch current resolution to a ramdom
 * 							valid resolution to test video encode
 * 							switch resolution function
 * return: 0 on success, -1 failed;
 */
 #if 0
static int venc_switch_resulution(void)
{
	ak_print_notice_ex("\t\t Switching resolution ...\n");

	static int current_res = 10;

	if(current_res == 10)
		current_res = 5;
	else
		current_res = 10;

	/* call vi interface to set new resolution */
	struct video_channel_attr attr;
	memset(&attr, 0, sizeof(struct video_channel_attr));

	attr.res[VIDEO_CHN_MAIN].width = resolutions[current_res].width;
	attr.res[VIDEO_CHN_MAIN].height = resolutions[current_res].height;
	//attr.res[VIDEO_CHN_SUB].width = resolutions[sub_index].width;
	//attr.res[VIDEO_CHN_SUB].height = resolutions[sub_index].height;
	attr.crop.left = 0;
	attr.crop.top = 0;
	attr.crop.width = resolutions[current_res].width;
	attr.crop.height = resolutions[current_res].height;

	/* change channel resolution */
	int ret = ak_vi_change_channel_attr(video_in_handle, &attr);
	if (ret) {
		ak_print_notice_ex("change attribute failed\n");
		return -1;
	}

	return 0;
}
#endif
/*
 * venc_switch_resulution - switch current resolution to a ramdom
 * 							valid resolution to test video encode
 * 							switch resolution function
 * return: 0 on success, -1 failed;
 */
static int venc_switch_video_bps(int kbps)
{
	ak_print_notice_ex("\t\t Switching bps to %d ...\n",kbps);

	ak_venc_set_rc(venc_handle, kbps);
	return 0;
}

/* open video encode handle */
static void *venc_demo_open_encoder()
{
	struct encode_param param = {0};

	//switch (0) {
	//case 0:
		param.width = 1280;
		param.height = 720;
		param.minqp = 20;
		param.maxqp = 51;
		param.fps = 25;
		param.goplen = param.fps;	   //current gop is stationary
		param.bps = 2000;				   //kbps
		param.profile = PROFILE_MAIN;	   //main profile
		param.use_chn = ENCODE_MAIN_CHN;   //use main yuv channel data
		param.enc_grp = ENCODE_RECORD;     //assignment from enum encode_group_type
		param.br_mode = BR_MODE_CBR;	   //default is cbr
		param.enc_out_type = H264_ENC_TYPE;//h.264
		//break;
#if 0
	case 1:
		param.width = resolutions[8].width;
		param.height = resolutions[8].height;
		param.minqp = 20;
		param.maxqp = 51;
		param.fps = 10;
		param.goplen = param.fps * 2;
		param.bps = 500;	//kbps
		param.profile = PROFILE_MAIN;		//same as above
		param.use_chn = ENCODE_MAIN_CHN;
		param.enc_grp = ENCODE_MAINCHN_NET;	//just this scope difference
		param.br_mode = BR_MODE_CBR;
		param.enc_out_type = H264_ENC_TYPE;
		break;
	case 2:
		param.width = resolutions[0].width;
		param.height = resolutions[0].height;
		param.minqp = 20;
		param.maxqp = 51;
		param.fps = 10;
		param.goplen = param.fps * 2;
		param.bps = 300;	//kbps
		param.profile = PROFILE_MAIN;
		param.use_chn = ENCODE_SUB_CHN;		//use sub yuv channel data
		param.enc_grp = ENCODE_SUBCHN_NET;	//same as above
		param.br_mode = BR_MODE_CBR;
		param.enc_out_type = H264_ENC_TYPE;
		break;
	case 3:
		param.width = resolutions[0].width;
		param.height = resolutions[0].height;
		param.minqp = 20;
		param.maxqp = 51;
		param.fps = 10;
		param.goplen = param.fps * 2;
		param.bps = 500;	//kbps
		param.profile = PROFILE_MAIN;
		param.use_chn = ENCODE_SUB_CHN;
		param.enc_grp = ENCODE_PICTURE;		//jpeg encode
		param.br_mode = BR_MODE_CBR;
		param.enc_out_type = MJPEG_ENC_TYPE;	//jpeg encode
		break;
#endif
	//default:
	//	return NULL;
	//	break;
	//}

	return ak_venc_open(&param);
}

/*
 * venc_save_stream_thread - save stream to file
 */
static void *venc_save_stream_thread(void *arg)
{
	long int tid = ak_thread_get_tid();
	ak_print_normal_ex("start a work thread, tid: %ld\n", tid);


	ak_print_error_ex("########### open ###########\n");
	//int looptimes = 1000;
//	int idx=0;

	/*
	 * according number of total save frame, iterate
	 * specific times
	 */
	while (1) {
		struct video_stream stream = {0};
		/* get stream */
		int ret = ak_venc_get_stream(stream_handle, &stream);
		if (ret) {
			ak_sleep_ms(10);
			continue;
		}
		//ak_print_normal_ex("[H264][tid: %ld] get stream, size: %d, last: %d\n",
		//		tid, stream.len, looptimes);

		/*
		 * save to file,
		 * Notice:
		 * 		on your project, replace your code to do
		 * 		your things here.
		 */

		if(stream.frame_type == 0x01)//sps pps i
		{
			memcpy(g_spsppsbuf,stream.data,stream.len);
			g_spsppslen = stream.len;
			g_b_I_frame_cap = 1;
		}
		g_len=0;

		memcpy(g_buf,stream.data,stream.len);
		g_len=stream.len;
				
		g_GetPackFlag=1;


		/* release frame */
		ret = ak_venc_release_stream(stream_handle, &stream);

		ak_sleep_ms(20);
	}


	return NULL;
}

static int init_software(void)
{
	/* just let we know what interface we use now */
	ak_pthread_t ak_venc_tid;			//thread id
	ak_net_get_cur_iface(NULL);

	int ret = AK_FAILED;
	if(AK_FAILED == init_video()) {
		goto software_end;
	}

	if(AK_FAILED == init_audio()) {
		goto software_end;
	}
	
	venc_handle = venc_demo_open_encoder();
	stream_handle = ak_venc_request_stream(vi_handle,venc_handle);
	/* create thread to get stream and do you primary mission */	
	ak_thread_create(&ak_venc_tid, venc_save_stream_thread,	NULL, 100*1024, -1);	

    ak_csrv_cmd_init_server(parse_cmd);
	/* init voice play module */
	ak_misc_init_voice_tips(ao_handle);

	if (ak_misc_ipc_first_run()) {
		struct audio_param file_param = {AK_AUDIO_TYPE_MP3, 8000, 16, 1};
		ak_misc_add_voice_tips("/usr/share/anyka_camera_start.mp3", &file_param);
	}

    //struct camera_disp_config *camera = ak_config_get_camera_info();
	/* start photosensitive ircut detect service */
	//ak_misc_start_photosensitive_switch(camera->day_ctrl);
#if 0
	struct sys_cloud_config *cloud = ak_config_get_sys_cloud();

	/* decide what cloud we configured support */
#ifdef CONFIG_ONVIF_SUPPORT
	if(cloud->onvif && !cloud->rtsp) {
		ak_print_normal("\n\t--- going to start onvif ---\n");
		init_onvif();
        ak_print_normal("\t--- start onvif ok ---\n\n");
	}
#endif

#ifdef CONFIG_RTSP_SUPPORT
	if(cloud->rtsp && !cloud->onvif) {
	    init_rtsp();
	}
#endif

#ifdef CONFIG_DANA_SUPPORT
	if(cloud->dana && !cloud->tencent){
		ak_dana_init(vi_handle, ai_handle, ao_handle);
	}
#endif
#endif


	struct video_record_config *record = ak_config_get_record();
	if (record->server_flag) {
		/* make sure we use only one cloud platform */
		// if(cloud->tencent && !cloud->dana) {
		// 	record_ctrl_init(vi_handle, ai_handle, DVR_FILE_TYPE_MP4);
		// }
		// if(cloud->dana && !cloud->tencent) {
		// 	record_ctrl_init(vi_handle, ai_handle, DVR_FILE_TYPE_AVI);
		// }
		//====== 2018 05 21 ======= mq
		//record_ctrl_init(vi_handle, ai_handle, DVR_FILE_TYPE_MP4);
	}

	ret = AK_SUCCESS;

software_end:
	if (AK_FAILED == ret) {
		if (vi_handle) {
			ak_vi_close(vi_handle);
			vi_handle = NULL;
		}
		if (ai_handle) {
			ak_ai_close(ai_handle);
			ai_handle = NULL;
		}
		if (ao_handle) {
			ak_ao_close(ao_handle);
			ao_handle = NULL;
		}
	}

	return ret;
}

static void process_signal(unsigned int sig, siginfo_t *si, void *ptr)
{
	if(ipc_run_flag) {
 		ak_backtrace(sig, si, ptr);
 	}

	if((SIGSEGV == sig) || (SIGTERM == sig) || (SIGINT == sig)){
		ipc_run_flag = 0;
	}
}

static int register_signal(void)
{
	struct sigaction s;

	s.sa_flags = SA_SIGINFO;
	s.sa_sigaction = (void *)process_signal;

	/* register signals that we should handle */
	sigaction(SIGSEGV, &s, NULL);
	sigaction(SIGINT, &s, NULL);
	sigaction(SIGTERM, &s, NULL);
	sigaction(SIGUSR1, &s, NULL);
	sigaction(SIGUSR2, &s, NULL);
	sigaction(SIGALRM, &s, NULL);
	sigaction(SIGHUP, &s, NULL);
	sigaction(SIGPIPE, &s, NULL);

	signal(SIGCHLD, SIG_IGN);

	return 0;
}

void *handle_android_send_audio(void * argv)
{

	printf("in handle_android\n");
//    size_t n;
//	int ret;
//	char buf_tmp[100]={0};
//	char read_tmp_buffer[SendLen];
//	int len=0;
//	int i=0;
	//OpenBitstreamFile("./test.h264");
	//int fd;
	//fd = open("test.h264", O_RDONLY);
	//if(-1 == fd){
	//	printf("file open error\n");
//
	//}
	//int read_len = 0;
	int remainLen=0,send_len=0,sendIndex=0;
	usleep(100*1000);
	
	for(;;)
	{
		if(g_GetPackAudioFlag  == 0x01)
		{

			g_GetPackAudioFlag=0;
			//for (i = 0; i < stVStream.u32PackCount; i++)
			//{
			
				remainLen=g_aac_len;
				sendIndex=0;
				//printf("g_len=%d\n",g_len);
				//for(idx=0;idx<30;idx++)
				//	printf(" %02x",g_buf[idx]);
				//printf("\n",g_len);
				while(remainLen>0)
				{

					send_len=send(socket_handle_audio, g_aacbuf+sendIndex, remainLen>=SendLen ? SendLen:remainLen, 0);

					if(send_len==-1)
						break;
					if(send_len!=0)
					{
						remainLen-=send_len;
						sendIndex+=send_len;
						//printf("file send_len=%d\n",send_len);
						//usleep(20*1000);
						//recv(tmp_android, read_tmp_buffer, 11, 0);
					}
					//else
					//	printf("send_len=%d\n",send_len);
					
					//printf("remainLen=%d\n",remainLen);
					//usleep(1*1000);
				}
				if(send_len==-1)
						break;
			//}	
		}
		usleep(100);
	}

	close(socket_handle_audio);
	
	printf("handle_android exit\n");
	pthread_exit(NULL);
}


void *handle_android_send2(void * argv)
{

	printf("in handle_android\n");
//    size_t n;
//	int ret;
//	char buf_tmp[100]={0};
//	char read_tmp_buffer[SendLen];
//	int len=0;
//	int i=0;
	//OpenBitstreamFile("./test.h264");
	//int fd;
	//fd = open("test.h264", O_RDONLY);
	//if(-1 == fd){
	//	printf("file open error\n");
//
	//}
	//int read_len = 0;
	int remainLen=0,send_len=0,sendIndex=0;
	usleep(100*1000);

	send(tmp_android, g_spsppsbuf, g_spsppslen, 0);	
	remainLen = g_spsppslen;

	while(remainLen>0)
	{
		if(sendIndex+remainLen>=SendLen ? SendLen:remainLen < BUFF_SIZE)
			send_len=send(tmp_android, g_spsppsbuf+sendIndex, remainLen>=SendLen ? SendLen:remainLen, 0);
		else
			printf("###############sendIndex=%d#############\n",sendIndex+remainLen>=SendLen ? SendLen:remainLen);
		if(send_len==-1)
			break;
		if(send_len!=0)
		{
			remainLen-=send_len;
			sendIndex+=send_len;
			//printf("file send_len=%d\n",send_len);
			//usleep(20*1000);
			//recv(tmp_android, read_tmp_buffer, 11, 0);
		}
		//else
		//	printf("send_len=%d\n",send_len);
		
		//printf("remainLen=%d\n",remainLen);
		//usleep(1*1000);
	}
	g_b_I_frame_cap = 0;

	while(g_b_I_frame_cap == 0)
	{
		usleep(1*100);
	}
	
	for(;;)
	{
		if(g_GetPackFlag  == 0x01)
		{

			g_GetPackFlag=0;
			//for (i = 0; i < stVStream.u32PackCount; i++)
			//{
			
				remainLen=g_len;
				sendIndex=0;
				//printf("g_len=%d\n",g_len);
				//for(idx=0;idx<30;idx++)
				//	printf(" %02x",g_buf[idx]);
				//printf("\n",g_len);
				while(remainLen>0)
				{

					send_len=send(tmp_android, g_buf+sendIndex, remainLen>=SendLen ? SendLen:remainLen, 0);

					if(send_len==-1)
						break;
					if(send_len!=0)
					{
						remainLen-=send_len;
						sendIndex+=send_len;
						//printf("file send_len=%d\n",send_len);
						//usleep(20*1000);
						//recv(tmp_android, read_tmp_buffer, 11, 0);
					}
					//else
					//	printf("send_len=%d\n",send_len);
					
					//printf("remainLen=%d\n",remainLen);
					//usleep(1*1000);
				}
				if(send_len==-1)
						break;
			//}	
		}
		usleep(100);
	}
	g_b_I_frame_cap = 0;
//	close(fd);
	close(tmp_android);
	
	printf("handle_android exit\n");
	pthread_exit(NULL);
}

void *BidCase_goSocketLoopAudio(void * argv)
{
	printf("in thread BidCase_goSocketLoopAudio\n");
	int fd=0;
	int socket_fd;

	pthread_t thread;
	int  serverPort = 7890;
	struct sockaddr_in servaddr;
	struct sockaddr_in cliaddr;
	char buf[MAXLINE];
	socklen_t socklen;
	socklen = sizeof(cliaddr);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(serverPort);
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
	    perror("socket error");
	    return NULL;
    }

    if (bind(fd, (struct sockaddr *) &servaddr, socklen) < 0) {
        perror("bind error");
        return NULL;
    }
	
    if (listen(fd, listenq) < 0) {
        perror("listen error");    
        return NULL;
    } 

	printf("andrpid -- echo server startup,listen on port:%d\n", serverPort);
    for ( ; ; )  
	{
        socket_handle_audio = accept(fd, (struct sockaddr *)&cliaddr, &socklen);
        if (socket_handle_audio < 0) 
		{
            perror("accept error");
            continue;
        }
        sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
        printf(buf,"");		
				
		if((socket_fd = pthread_create(&thread, NULL, handle_android_send_audio, NULL)) != 0)		
			printf("create thread_to_process_Android error!\n");
    }
}

void *BidCase_goSocketLoop(void * argv)
{
	printf("in thread thread_to_process_Android\n");
	int fd=0;
	int socket_fd;

	pthread_t thread;
	int  serverPort = 7777;
	struct sockaddr_in servaddr;
	struct sockaddr_in cliaddr;
	char buf[MAXLINE];
	socklen_t socklen;
	socklen = sizeof(cliaddr);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(serverPort);
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
	    perror("socket error");
	    return NULL;
    }

    if (bind(fd, (struct sockaddr *) &servaddr, socklen) < 0) {
        perror("bind error");
        return NULL;
    }
	
    if (listen(fd, listenq) < 0) {
        perror("listen error");    
        return NULL;
    } 

	printf("andrpid -- echo server startup,listen on port:%d\n", serverPort);
    for ( ; ; )  
	{
        tmp_android = accept(fd, (struct sockaddr *)&cliaddr, &socklen);
        if (tmp_android < 0) 
		{
            perror("accept error");
            continue;
        }
        sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
        printf(buf,"");		
				
		if((socket_fd = pthread_create(&thread, NULL, handle_android_send2, NULL)) != 0)		
			printf("create thread_to_process_Android error!\n");
    }
}


/**
 * ak_get_sdcard_total_size - get sd card total size 
 * @path[IN]: 	 sd card mount point path   
 * return:   >0 ,   sd card total size;  -1 , failed;
 */
 uint64_t ak_get_sdcard_total_size_my(char *path)
 {

 	uint64_t total_size = 0;
 	struct statfs disk_statfs;

 	memset(&disk_statfs,0, sizeof( struct statfs ) );
 	while ( statfs( path, &disk_statfs ) == -1 ) {
 		if ( errno != EINTR ) {
 			ak_print_normal( "statfs: %s Last error == %s\n", path, strerror(errno) );
			return -1;
 		}
 	}
 	total_size = disk_statfs.f_bsize;
 	total_size = total_size * disk_statfs.f_blocks;

 	return total_size;
 }
 uint64_t ak_get_sdcard_free_size_my(char *path)
 {

	uint64_t free_size = 0;
	struct statfs disk_statfs;

	bzero(&disk_statfs, sizeof( struct statfs ) );
	while ( statfs( path, &disk_statfs ) == -1 ) {
		if ( errno != EINTR ) {
			ak_print_normal( "statfs: %s Last error == %s\n", path, strerror(errno) );
			return -1;
		}
	}
	free_size = disk_statfs.f_bsize;
	free_size = free_size * disk_statfs.f_bavail;

	return free_size;

 }

#define SERVER_PORT 8000
#define SDC_PATH 			"/mnt/"
extern void *ak_config_set_record_time(int time_ms);

void *message_init(void * argv)
{
    struct sockaddr_in serveraddr, clientaddr;
    int sockfd, addrlen, confd;
    char ipstr[128];
    char buf[MAXLINE];

    //1.socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    //2.bind
    bzero(&serveraddr, sizeof(serveraddr));
    /* 地址族协议IPv4 */
    serveraddr.sin_family = AF_INET;
    /* IP地址 */
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(SERVER_PORT);
    bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    //3.listen
    listen(sockfd, 128);
    while (1) {
        //4.accept阻塞监听客户端链接请求
        addrlen = sizeof(clientaddr);
        confd = accept(sockfd, (struct sockaddr *)&clientaddr, (socklen_t *)&addrlen);//返回的是客户端和服务端专用通道的socket描述符
        //输出客户端IP地址和端口号
        inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, ipstr, sizeof(ipstr));
        printf("client ip %s\tport %d\n", 
                inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, ipstr, sizeof(ipstr)),
                ntohs(clientaddr.sin_port));

        //和客户端交互数据操作confd
        //5.处理客户端请求 
        read(confd, buf, sizeof(buf));
		printf("read : %s\n",buf);
		if(strncmp(buf,"001",3)==0)
		{
			//sn版本号
			// write(confd, "test sn !!!", strlen("test sn !!!")+1);
			FILE *fp;
			char load_file[256] = "/sys/kernel/serial_number/sn";
			char line[1000];
			fp=fopen(load_file,"r");
			if(fp==NULL)
			{
				printf("can not load file!");
				//return NULL;
			}
			while(!feof(fp))
			{
				fgets(line,1000,fp);
				
			}
			printf("sn=%s",line);
			write(confd, line, strlen(line)+1);
			fclose(fp);

		}
		else if(strncmp(buf,"002",3)==0)
		{
			//MAC地址

			FILE *fp;
			char load_file[256] = "/sys/class/net/wlan0/address";
			char line[1000];
			fp=fopen(load_file,"r");
			if(fp==NULL)
			{
				printf("can not load file!");
				//return NULL;
			}
			while(!feof(fp))
			{
				fgets(line,1000,fp);
				
			}
			printf("%s",line);
			write(confd, line, strlen(line)+1);
			fclose(fp);

		}
		else if(strncmp(buf,"003",3)==0)
		{
			//电量
			system("cat /sys/pctrl_gpio/bat_vol > /tmp/bat.txt");
			FILE *fp;
			char load_file[256] = "/tmp/bat.txt";
			char line[1000];
			fp=fopen(load_file,"r");
			if(fp==NULL)
			{
				printf("can not load file!");
				//return NULL;
			}
			//while(!feof(fp))
			//{
			//	fgets(line,1000,fp);
			//	printf("%s\n", fgets(line,1000,fp));
			//	
			//}
			fread(line,sizeof(char),4,fp);
			line[4] = '\0';
			printf("power===%s===",line);
			write(confd, line, strlen(line)+1);
			fclose(fp);
		}		
		else if(strncmp(buf,"004",3)==0)
		{
			//tf卡容量
			uint64_t sdc_size = ak_get_sdcard_total_size_my(SDC_PATH);	/** get sd card total size **/
			printf("sdc_total_size = %lld\n",sdc_size);
			char str[25];
			sprintf(str, "%lld\n", sdc_size);
			write(confd, str, strlen(str)+1);

		}
		else if(strncmp(buf,"005",3)==0)
		{
			//tf卡容量
			uint64_t sdc_size = ak_get_sdcard_free_size_my(SDC_PATH);	/** get sd card total size **/
			printf("sdc_free_size = %lld\n",sdc_size);
			char str[25];
			sprintf(str, "%lld\n", sdc_size);
			write(confd, str, strlen(str)+1);

		}
		else if(strncmp(buf,"006",3)==0)
		{
			//version
			char str[25];
			sprintf(str, "%s\n", AK_VERSION_SOFTWARE);
			write(confd, str, strlen(str)+1);

		}
		else if(strncmp(buf,"007",3)==0)
		{
			//设置录像时长
			uint32_t record_dur = 10*(buf[3]-'0') + (buf[4]-'0');
			printf("%d\n",record_dur );
			if(record_dur > 0){
				ak_config_set_record_time(record_dur*60);
				char isOk[25] = "OK";
			    write(confd, isOk, strlen(isOk)+1);
			}
		}
		else if(strncmp(buf,"008",3)==0)
		{
			//设置预览分辨率和存储分辨率
			//venc_switch_resulution();
			switch(buf[3])
			{
				case '0':
					venc_switch_video_bps(4000);
					printf("set bps 4000\n");
				break;
				case '1':
					venc_switch_video_bps(2000);
					printf("set bps 2000\n");
				break;
				case '2':
					venc_switch_video_bps(500);
					printf("set bps 500\n");
				break;
				default:
				break;
			}
		}
		else if(strncmp(buf,"009",3)==0)//更新系统时间 格式：009-xxxx-xx-xx-xx:xx:xx //年月日时分秒
		{
			char date[64] = "";
			char cmd_line[128] = "";
			strncpy(date, buf+4, 10);
			date[11] = '\0';
			sprintf(cmd_line, "date -s %s",date);
			printf("cmd_line date = %s\n",cmd_line);
			system(cmd_line);
			
			char time[64] = "";

			strncpy(time, buf+15, 8);
			time[9] = '\0';
			memset(cmd_line, 0, sizeof(cmd_line));
			sprintf(cmd_line, "date -s %s",time);
			printf("cmd_line time = %s\n",cmd_line);
			system(cmd_line);
			//save to rtc
			system("hwclock -w");
			char isOk[25] = "OK";
			write(confd, isOk, strlen(isOk)+1);
		}
		else if(strncmp(buf,"010",3)==0)//开始停在录制
		{
			if(buf[3]=='0')
			{
				//停止录像api
			}
			else
			{
				//开始录制api
			}
		}
		#if 0
        i = 0;
        while (i < len) {
            buf[i] = toupper(buf[i]);
            i++;
        }
        write(confd, buf, len);
		#endif
		usleep(200*1000);
        close(confd);
    }
    close(sockfd);

    return NULL;
}
extern void *ak_config_set_sys_wifi_ap(char *name);
extern void save_record_reboot(void);
#define AP_NAME 			"StayActive-"
void midstr(char *dp,char *sp,int s,int l)
{
	int i;
	s = s-1;
	if(s>=0&&l>0)
	{
		for(i=s;i<s+l&&sp[i]!=0;i++){
			dp[i-s] = sp[i];
		}
		dp[i-s]=0;
	}
	else
		dp[0]=0;
}
void *save_last(void *argv){

while(1){
	system("cat /sys/pctrl_gpio/stop_st > /tmp/bat.txt");
			FILE *fp;
			char load_file[256] = "/tmp/bat.txt";
			char sn[1000];
			fp=fopen(load_file,"r");
			if(fp==NULL)
			{
				printf("can not load file!");
				//return NULL;
			}
			
			fread(sn,sizeof(char),4,fp);
			fclose(fp);
			
			
			if (atoi(sn) == 100)
			{
				system("echo 101 > /sys/pctrl_gpio/stop_st");
				printf("======reboot > 100=======\n");
				
			}else if (atoi(sn) == 101)
			{   
				if (save_last_flag == 0)
				{
					printf("======reboot > 101=======\n");
					save_record_reboot();
					system("echo 0 > sys/user-gpio/gpio-r");
					system("echo 0 > sys/user-gpio/gpio-g");
					system("reboot");
					save_last_flag = 1;
				}
				
			}
			usleep(100*1000);
}

	return NULL;
}
void *get_udc(void *argv){

	while(1){	

		system("cat /proc/driver/udc > /tmp/bat1.txt");
			FILE *fp;
			char load_file[256] = "/tmp/bat1.txt";
			char sn[1000];
			fp=fopen(load_file,"r");
			if(fp==NULL)
			{
				printf("can not load file!");
				//return NULL;
			}
			
			fread(sn,sizeof(char),1,fp);
			fclose(fp);
			//printf("=====udc listen=====%s",sn);
			
		if(atoi(sn) == 1){
			//printf("=== connect usb === %d\n",udc_value );
			if (udc_value == 0)
			{
				system("/usr/sbin/udisk.sh start");
				udc_value = 1;
				//printf("==============udisk.sh start==============\n");
			}
		}
		else
		{
			//printf("=== disconnect usb === %d\n",udc_value );
			if (udc_value == 1)
			{
				//system("/usr/sbin/udisk.sh stop");
				udc_value = 0;
				//printf("==========udisk.sh stop==========\n");
			}
		}
			//1 s 10 
		usleep(200*1000);
	}
	return NULL;
}
int StrToInt(char *s)  // 将一个字符串转化为整数
{
int number=0;
while(*s!='\0')
{
number=number*10+*s-'0';
s++;
}
return number;
}

/**  
 * write_stream_to_file - write stream to audio record file
 * @stream_head[IN]: stream list head
 * notes: 
 */
int g_is_file_opened = 0;
static void write_stream_to_file(struct list_head *stream_head)
{
	struct aenc_entry *entry = NULL;
	struct aenc_entry *ptr = NULL;
	int idx=0;

	if(g_is_file_opened == 0)
	{
		g_is_file_opened = 1;
		aenc.fp=fopen("/mnt/test00000.amr","wb+");
		if(aenc.fp==NULL)
		{
			printf("can not load file!");
			//return NULL;
		}	

		/* write AMR file head */
		//if (AK_AUDIO_TYPE_AMR == enc_type) {
			const unsigned char amrheader[]= "#!AMR\n";
			fwrite(amrheader, sizeof(amrheader) - 1, 1, aenc.fp);
		//}

	}

	list_for_each_entry_safe(entry, ptr, stream_head, list) {
		if(entry) {
		/* write data to file */
			// printf("get aac buf len = %d\n", entry->stream.len);
		for(idx=0;idx<20;idx++)
			printf("%02x ",entry->stream.data[idx]);
		
			memcpy(g_aacbuf, entry->stream.data, entry->stream.len);
			g_aac_len = entry->stream.len;
			g_GetPackAudioFlag = 1;
			if(fwrite(entry->stream.data, entry->stream.len, 1, aenc.fp) < 0) {
				ak_print_error_ex("write file err\n");
			}
		}
		/* after write to file,release stream */
		ak_aenc_release_stream(entry);
	}
}

static void write_record_file(void *stream_handle)
{
	struct ak_timeval enc_time;
	struct ak_timeval cur_time;
	struct list_head stream_head;
	
	INIT_LIST_HEAD(&stream_head);
	ak_get_ostime(&enc_time);
	ak_get_ostime(&cur_time);
	while(AK_TRUE) {

		/* get audio stream list */
		if (!ak_aenc_get_stream(stream_handle, &stream_head)) {
			/* write data to file */
			write_stream_to_file(&stream_head);
		}	
        ak_sleep_ms(10);
	}
	ak_print_normal_ex("thread exit\n\n");
}

void *ak_aenv_start(void * argv)
{

/*------------init aenc start-------------------*/
	/*  open audio encode */
	struct audio_param aenc_param = {0};
	struct video_record_config *record_config = ak_config_get_record();

	aenc_param.type = AK_AUDIO_TYPE_AMR;
	aenc_param.sample_bits = 16;
	aenc_param.channel_num = AUDIO_CHANNEL_MONO;
	aenc_param.sample_rate = record_config->sample_rate;

    void *aenc_handle = ak_aenc_open(&aenc_param);
	if (!aenc_handle) {
    	return NULL;
    }

	if (ak_ai_set_source(ai_handle, AI_SOURCE_MIC))
		ak_print_error_ex("set ai source mic fail\n");
	else
		ak_print_normal_ex("set ai source mic success\n");

	if (AK_SUCCESS == ak_ai_set_frame_interval(ai_handle, AUDIO_DEFAULT_INTERVAL)) {
		ak_print_normal("ai frame interval=%d\n", AUDIO_DEFAULT_INTERVAL);
	}
	ak_ai_start_capture(ai_handle);

/*-------------------init aenc end----------------------*/

	/* bind audio input & encode */
	void *stream_handle = ak_aenc_request_stream(ai_handle, aenc_handle);
	if (NULL == stream_handle) {
		ak_print_error_ex("ak_aenc_request_stream failed\n");
		return NULL;
    	//goto aenc_end;
    }
    ak_print_normal("ak_aenc_request_stream OK\n");


    /* get audio stream and write it to file */
    write_record_file(stream_handle);

	if (NULL != stream_handle) {
    	ak_aenc_cancel_stream(stream_handle);
    	stream_handle = NULL;
    }
#if 0
aenc_end:
	if (NULL != aenc_handle) {
		/* aenc close */
    	ak_aenc_close(aenc_handle);
    	aenc_handle = NULL;
    }

ai_end:
    if (NULL != ai_handle) {
    	/* ai close */
    	ak_ai_close(ai_handle);
    	ai_handle = NULL;
    }

fp_end:
    if (NULL != aenc.fp) {
    	fclose(aenc.fp);
    	aenc.fp = NULL;
    }
//    printf("----- %s exit -----\n", argv[0]);
#endif
	return NULL;
}

/* create file to save stream */
static void *venc_open_file(int enc_type)
{
	char file[128] = {0};
	char time_str[32] = {0};
	//const char *suffix[2] = {".h264", ".jpg"};
	struct ak_date date;

	/* get time string */
	ak_get_localdate(&date);
	ak_date_to_string(&date, time_str);

	/* distinguish h.264 and jpeg */
	if (enc_type < ENCODE_PICTURE) {
		//sprintf(file, "%s/%s_%d_%s", SAVE_PATH, time_str, enc_type, suffix[0]);
		//ak_print_normal_ex("[ H264 ] save file: %s\n", file);
	} else {
		//sprintf(file, "%s/%s_%d_%s", SAVE_PATH, time_str, (rand() & 0xff), suffix[1]);
		sprintf(file, "%s", "/mnt/video_encode/snap.jpg");
	
		ak_print_normal_ex("[ JPG ] save file: %s\n", file);
	}

	/* open for all mode */
	FILE *fp = NULL;
	fp = fopen(file, "a");
	if (!fp) {
		ak_print_error_ex("open [%s] failed, %s\n", file, strerror(errno));
		return NULL;
	}

	return fp;
}

/* save data */
static void venc_save_data(FILE *filp, unsigned char *data, int len)
{
	int ret = len;
	if (filp) {
		/* make sure all data were writ to file */
		do {
			ret -= fwrite(data, 1, ret, filp);
		} while (ret > 0);
	}
}

void venc_test_picture(void)
{
	int test_times = 5;

	ak_print_normal_ex("begin\n");
	while (test_times > 0) {
		struct video_input_frame f;
		struct video_stream s;
		void *picture;

		/* get yuv by sigle step */
		if (!ak_vi_get_frame(vi_handle, &f)) {
			/* open encoder */
			picture = venc_demo_open_encoder(ENCODE_PICTURE);

			/* sigle encode mode */
			ak_venc_send_frame(picture, f.vi_frame[VIDEO_CHN_SUB].data,
					f.vi_frame[VIDEO_CHN_SUB].len, &s);
			/*
			 * release yuv, notice that the time you occupy
			 * yuv should as little as possible
			 */
			ak_vi_release_frame(vi_handle, &f);

			/* do you primary things here */
			FILE *fp = venc_open_file(ENCODE_PICTURE);
			if (fp) {
				venc_save_data(fp, s.data, s.len);
				fclose(fp);
			}

			/* after procee, close encoder */
			ak_venc_close(picture);
			free(s.data);
			test_times--;
			ak_sleep_ms(1000);
		} else
			ak_sleep_ms(20);
	}
	ak_print_normal_ex("end\n");
}

void *ak_aenv_snap_proc(void * argv)
{
	for(;;)
	{
		venc_test_picture();
		printf("snap a frame ... \n");
		system("/mnt/zxing /mnt/video_encode/snap.jpg");
		usleep(200*1000);
	}
}

int ipc_init_wifi()
{
	//sn版本号
	FILE *fp;
	char load_file[256] = "/sys/kernel/serial_number/sn";
	char sn[1000];
	fp=fopen(load_file,"r");
	if(fp==NULL)
	{
		printf("can not load file!");
		//return NULL;
	}
	while(!feof(fp))
	{
		fgets(sn,1000,fp);
			
	}
	printf("sn=%s",sn);
	fclose(fp);
	char strName[80],ssn[18]={0};
	strcpy(strName,AP_NAME);
	midstr(ssn,sn,1,4);
	strcat(strName,ssn);
	printf("AP_name======%s\n", strName);
	ak_config_set_sys_wifi_ap(strName);
	return 0;
}

int main(void)
{
	ak_print_normal("\n*******************************************************\n");
	ak_print_normal("\t %s_build@%s_%s\n",
			AK_VERSION_SOFTWARE, __DATE__, __TIME__);
	ak_print_normal("*******************************************************\n\n");
	/* print audio version and functions that we support */
	ak_ai_print_filter_info();
	ak_aenc_print_codec_info();
	ak_print_normal("\n");

	static pthread_t VencPid_2;
	pthread_create(&VencPid_2, 0, BidCase_goSocketLoop, NULL);

	static pthread_t VencPid_audio;
	pthread_create(&VencPid_audio, 0, BidCase_goSocketLoopAudio, NULL);

	static pthread_t message;
	pthread_create(&message, 0, message_init, NULL);

	static pthread_t save_lastVideo;
	pthread_create(&save_lastVideo, 0, save_last, NULL);

	static pthread_t get_udc_status;
	pthread_create(&get_udc_status, 0, get_udc, NULL);

	ipc_run_flag = 1;
	register_signal();
	start_monitor_th();
	
	printf("==========init_ini=========\n");
	/** load config message, than init it **/
	ak_config_init_ini();
	ipc_init_wifi();
	printf("==========init_ini_end=========\n");
	
	init_hardware();
	if(init_software()){
		return -1;
	}

	// static pthread_t VencPid_snap;
	// pthread_create(&VencPid_snap, 0, ak_aenv_snap_proc, NULL);
	
	static pthread_t VencPid_Aenc;
	pthread_create(&VencPid_Aenc, 0, ak_aenv_start, NULL);

	while (ipc_run_flag) {
		ak_sleep_ms(1000);
	}
	exit_ipc_app();

	return 0;
}
